home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / WILDMAT.C < prev    next >
Text File  |  1993-10-09  |  4KB  |  124 lines

  1. /*
  2.  * @(#)wildmat.c 1.3 87/11/06    Public Domain.
  3.  *
  4. From: rs@mirror.TMC.COM (Rich Salz)
  5. Newsgroups: net.sources
  6. Subject: Small shell-style pattern matcher
  7. Message-ID: <596@mirror.TMC.COM>
  8. Date: 27 Nov 86 00:06:40 GMT
  9.  
  10. There have been several regular-expression subroutines and one or two
  11. filename-globbing routines in mod.sources.  They handle lots of
  12. complicated patterns.  This small piece of code handles the *?[]\
  13. wildcard characters the way the standard Unix(tm) shells do, with the
  14. addition that "[^.....]" is an inverse character class -- it matches
  15. any character not in the range ".....".  Read the comments for more
  16. info.
  17.  
  18. For my application, I had first ripped off a copy of the "glob" routine
  19. from within the find(1) source, but that code is bad news:  it recurses
  20. on every character in the pattern.  I'm putting this replacement in the
  21. public domain.  It's small, tight, and iterative.  Compile with -DTEST
  22. to get a test driver.  After you're convinced it works, install in
  23. whatever way is appropriate for you.
  24.  
  25. I would like to hear of bugs, but am not interested in additions; if I
  26. were, I'd use the code I mentioned above.
  27. */
  28. /*
  29. **  Do shell-style pattern matching for ?, \, [], and * characters.
  30. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  31. **  could cause a segmentation violation.
  32. **
  33. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  34. */
  35.  
  36. /*
  37.  * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
  38.  * if the pattern is immediately followed by a "/", as well as \0.
  39.  * This matches what "tar" does for matching whole subdirectories.
  40.  *
  41.  * The "*" code could be sped up by only recursing one level instead
  42.  * of two for each trial pattern, perhaps, and not recursing at all
  43.  * if a literal match of the next 2 chars would fail.
  44.  */
  45.  
  46. /* Modified by Anders Klemets to take an array of pointers as an optional
  47.    argument. Each part of the string that matches '*' is returned as a
  48.    null-terminated, malloced string in this array.
  49.  */
  50. #include "global.h"
  51.  
  52. static int near
  53. Star(char *s,char *p,char **argv)
  54. {
  55.     char *cp = s;
  56.  
  57.     while (wildmat(cp, p, argv) == FALSE) {
  58.         if(*++cp == '\0') {
  59.             return -1;
  60.         }
  61.     }
  62.     return (int)(cp - s);
  63. }
  64.  
  65. int
  66. wildmat(char *s,char *p,char **argv)
  67. {
  68.     int last, matched, reverse, cnt;
  69.  
  70.     for(; *p; s++, p++) {
  71.         switch(*p){
  72.         case '\\':
  73.             /* Literal match with following character; fall through. */
  74.             p++;
  75.         default:
  76.             if(*s != *p) {
  77.                 return FALSE;
  78.             }
  79.             continue;
  80.         case '?':
  81.             /* Match anything. */
  82.             if(*s == '\0') {
  83.                 return FALSE;
  84.             }
  85.             continue;
  86.         case '*':
  87.             /* Trailing star matches everything. */
  88.             if(argv == NULLCHARP) {
  89.                 return (*++p ? (1 + Star(s, p, NULLCHARP)) : TRUE);
  90.             }
  91.             if(*++p == '\0') {
  92.                 cnt = strlen(s);
  93.             } else {
  94.                 if((cnt = Star(s, p, argv+1)) == -1) {
  95.                     return FALSE;
  96.                 }
  97.             }
  98.             *argv = mxallocw(cnt + 1);
  99.             strncpy(*argv,s,cnt);
  100.             *(*argv + cnt) = '\0';
  101.             return TRUE;
  102.         case '[':
  103.             /* [^....] means inverse character class. */
  104.             reverse = (p[1] == '^') ? TRUE : FALSE;
  105.  
  106.             if(reverse) {
  107.                 p++;
  108.             }
  109.             for(last = 0400, matched = FALSE; *++p && *p != ']'; last = *p) {
  110.                 /* This next line requires a good C compiler. */
  111.                 if((*p == '-') ? ((*s <= *++p) && (*s >= last)) : (*s == *p)) {
  112.                     matched = TRUE;
  113.                 }
  114.             }
  115.             if(matched == reverse) {
  116.                 return FALSE;
  117.             }
  118.             continue;
  119.         }
  120.     }
  121.     /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
  122.     return (*s == '\0' || *s == '/');
  123. }
  124.